// Author	: damphat@gmail.com
// Created	: 01/12/2008

#pragma once
#include "vn/BasicTypes.h"
#include <assert.h>

template<class T>
size_t StrLen(const T* psz) {
	if(!psz) return 0;
	const T* ptr = psz;
	while(*ptr) ptr++;
	return (ptr - psz);
}

template<class T, class U>
void StrCpy(T* des, const U* src, size_t len) {
	for(size_t i=0; i<len; i++) {
		des[i] = src[i];
	}
}

template<>
static void StrCpy<Char, WChar>(LPChar des, LPCWChar src, size_t len) {
	for(size_t i=0; i<len; i++) {
		if(src[i] > 255)
			des[i] = '?';
		else
			des[i] = (Char)src[i];
	}
}

template<class T, class U>
int MemCmp(const T* a, const U* b, size_t len) {
	for(size_t i=0; i<len; i++) {
		if(a[i] < b[i])
			return -1;
		else if(a[i] > b[i])
			return 1;
	}
	return 0;
}

template<class C1, class C2>
int StrCmp(const C1* a, const C2* b, size_t len) {
	return 0;
}

// Compare(String, String, bool,
// ToUpper
// ToLower

// String x = null???


template<class T>
class StringBase {
	template<class> friend class StringBase;
public:
	// constructors
	StringBase()
		: m_dat(0)
		, m_len(0)
	{ }

	template<class U>
	StringBase(const U* psz) {
		m_len = StrLen(psz);
		if(psz) {
			m_dat = new T[m_len+1];
			StrCpy(m_dat, psz, m_len + 1);
		}
		else {
			m_dat = 0;
		}
	}

	template<class U>
	StringBase(const U* buff, size_t len) {
		if((len < 0) || (buff == 0)) {
			buff = 0;
			len = 0;
		}

		m_len = len;
		if(buff) {
			m_dat = new T[m_len+1];
			StrCpy(m_dat, buff, m_len);
			m_dat[m_len] = 0;
		}
		else {
			m_dat = 0;
		}
	}

	// Error	1	error C2248: 'StringBase<T>::m_len' : cannot access private member declared in class 'StringBase<T>'	d:\remo\remo\string.hpp	76
	// Analysis: StringBase<Char> cannot access private members of <StringBase<WChar>
	// Solution:


	template<class U>
	StringBase(const StringBase<U> &val) {
		m_len = val.m_len;
		if(val.m_dat) {
			m_dat = new T[m_len+1];
			StrCpy(m_dat, val.m_dat, m_len + 1);
		}
		else {
			m_dat = 0;
		}
	}

	StringBase(const StringBase &val) {
		m_len = val.m_len;
		if(val.m_dat) {
			m_dat = new T[m_len+1];
			StrCpy(m_dat, val.m_dat, m_len + 1);
		}
		else {
			m_dat = 0;
		}
	}

	T* C_STR() {
		return m_dat;
	}


	const T* C_STR() const {
		return m_dat;
	}

	T& operator [] (size_t index) {
		assert(((index >= 0) || (index < m_len)));
		return m_dat[index];
	}

	const T& operator [] (size_t index) const {
		assert(((index >= 0) || (index < m_len)));
		return m_dat[index];
	}


	// Error	7	error C2446: '==' : no conversion from 'LPCChar' to 'LPWChar'	d:\remo\remo\string.hpp	120
	// Add '(void *)'

	template<class U>
	const StringBase& operator = (const U* psz) {
		if ((void *)m_dat == (void *)psz) {
			return *this;
		}

		if(m_dat)
			delete[] m_dat;

		m_len = StrLen(psz);
		if(psz) {
			m_dat = new T[m_len+1];
			StrCpy(m_dat, psz, m_len + 1);
		}
		else {
			m_dat = 0;
		}

		return *this;
	}

	template<class U>
	const StringBase& operator = (const StringBase<U> &val) {
		return (*this) = val.m_dat;
	}

	const StringBase& operator = (const StringBase &val) {
		return (*this) = val.m_dat;
	}


	template<class U>
	StringBase& operator += (const U* psz) {
		// s + null == s;
		if(!psz)
			return *this;

		size_t datLen = StrLen(psz);
		size_t newLen = m_len + datLen;
		T* temp = new T[newLen + 1];

		if(m_len) {
			StrCpy(temp, m_dat, m_len);
		}

		if(datLen) {
			StrCpy(temp + m_len, psz, datLen);
		}

		temp[newLen] = 0;

		if(m_dat)
			delete[] m_dat;

		m_dat = temp;
		m_len = newLen;

		return *this;
	}

	// Error	9	error C2784: 'const StringBase<T> &StringBase<T>::operator +=(const U *)' : could not deduce template argument for 'const U *' from 'StringA'	d:\remo\remo\stringtest.h	95
	// => add:

	template<class U>
	StringBase& operator += (const StringBase<U> &ref) {
		// Error	9	error C2039: 'm_data' : is not a member of 'StringBase<T>'	d:\remo\remo\string.h	167
		// spell: m_data -> m_dat
		(*this) += ref.m_dat;

		// Error	10	error C4716: 'StringBase<char>::operator+=<char>' : must return a value	d:\remo\remo\string.h	170
		return *this;
	}

	// get a sub string
	const StringBase Substring(size_t from, size_t count) const {
		assert(from + count <= m_len);
		return StringBase(m_dat + from, count);
	}

//	const StringBase ToLower() const {
//		String temp = m_dat;
//		for (size_t i=0; i<m_len; i++)
//			temp[i] = _totlower(temp[i]);
//		return temp;
//	}
//
//	const StringBase ToUpper() const {
//		String temp = m_dat;
//		for (int i=0; i<m_len; i++)
//			temp[i] = _totupper(temp[i]);
//		return temp;
//	}


	// len of string, length is mutable?
	size_t GetLength() const {
		return m_len;
	}

#ifdef _AFX
	operator CString () const {
		return m_dat;
	}
#endif

// Note: std::string is ansi version, so use std::basic_string<TCHAR, char_traits<TCHAR>
#ifdef _IOSTREAM_
	operator std::basic_string<TCHAR, char_traits<TCHAR> () const {
		return m_dat;
	}
#endif

	template <class U>
	bool operator == (const U* psz) const {
		// Error	9	error C2446: '==' : no conversion from 'LPCWChar' to 'LPCharconst '	d:\remo\remo\string.h	189
		// => add (void*)
		if((void*)m_dat == (void*)psz)
			return true;
		if((m_dat == 0) || (psz == 0))
			return false;
		size_t datLen = StrLen(psz);
		if(m_len != datLen)
			return false;
		int cmp = MemCmp(m_dat, psz, (m_len < datLen ? m_len : datLen) + 1);
		return cmp == 0;
	}

	// assert(aa == (LPChar)0);
	// Error	7	error C2666: 'StringBase<T>::operator ==' : 3 overloads have similar conversions	d:\remo\remo\stringtest.h	34




	// StringA b("12345"), c(b);
	// assert(b == c); // faile because (LPChar)b == (LPChar)c
	// >> replace operator *T with Str()

	// const StringA a;
	// assert(a==a);
	// Error	14	error C2678: binary '==' : no operator found which takes a left-hand operand of type 'const StringA' (or there is no acceptable conversion)	d:\remo\remo\stringtest.h	144
	// >> THIEU 'const' cho operator


	template <class U>
	bool operator == (const StringBase<U>& ref) const {
		return (*this) == ref.C_STR();
	}

	template <class U>
	bool operator != (const U* psz) const {
		return !((*this) == psz);
	}

	template <class U>
	bool operator != (const StringBase<U>& ref) const {
		return !((*this) == ref);
	}

	//template <class T>
	//friend std::basic_ostream<T, std::char_traits<T>> &operator <<
	//	(std::basic_ostream<T, std::char_traits<T>> &os, const StringBase<T> &str);


	virtual ~StringBase() {
		if(m_dat)
			delete[] m_dat;
	}

private:
	T*		m_dat;
	size_t	m_len;

};// class StringBase

//template <class T> std::basic_ostream<T, std::char_traits<T>> &operator <<
//	(std::basic_ostream<T, std::char_traits<T>> &os, const StringBase<T> &str);

typedef StringBase<Char>	StringA;
typedef StringBase<WChar>	StringW;

#ifdef _UNICODE
typedef StringW	String;
#else
typedef StringA	String;
#endif

// Improvement:
// String a = "GET " + path + " /HTTP/1.1";
//

template <class T1, class T2>
static StringBase<T1> operator + (const StringBase<T1> &a, const StringBase<T2> &b) {
	StringBase<T1> temp = a;
	temp += b;
	return temp;
}

template <class T1, class T2>
static StringBase<T1> operator + (const StringBase<T1> &a, const T2* b) {
	StringBase<T1> temp = a;
	temp += b;
	return temp;
}

template <class T1, class T2>
static StringBase<T1> operator + (const T1 *a, const StringBase<T2> &b) {
	StringBase<T1> temp = a;
	temp += b;
	return temp;
}
